home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Archives
/
GNU
/
GNUPLOTsrc.lha
/
scanner.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-22
|
11KB
|
396 lines
#ifndef lint
static char *RCSid = "$Id: scanner.c,v 1.49 1995/12/02 22:04:37 drd Exp $";
#endif
/* GNUPLOT - scanner.c */
/*
* Copyright (C) 1986 - 1993 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the modified code. Modifications are to be distributed
* as patches to released version.
*
* This software is provided "as is" without express or implied warranty.
*
*
* AUTHORS
*
* Original Software:
* Thomas Williams, Colin Kelley.
*
* Gnuplot 2.0 additions:
* Russell Lang, Dave Kotz, John Campbell.
*
* Gnuplot 3.0 additions:
* Gershon Elber and many others.
*
* There is a mailing list for gnuplot users. Note, however, that the
* newsgroup
* comp.graphics.gnuplot
* is identical to the mailing list (they
* both carry the same set of messages). We prefer that you read the
* messages through that newsgroup, to subscribing to the mailing list.
* (If you can read that newsgroup, and are already on the mailing list,
* please send a message info-gnuplot-request@dartmouth.edu, asking to be
* removed from the mailing list.)
*
* The address for mailing to list members is
* info-gnuplot@dartmouth.edu
* and for mailing administrative requests is
* info-gnuplot-request@dartmouth.edu
* The mailing list for bug reports is
* bug-gnuplot@dartmouth.edu
* The list of those interested in beta-test versions is
* info-gnuplot-beta@dartmouth.edu
*/
#include <ctype.h>
#include <math.h>
#include "plot.h"
static int get_num __P((char str[]));
static void substitute __P((char *str, int max));
#ifdef AMIGA_AC_5
#define O_RDONLY 0
int open(const char * _name, int _mode, ...);
int close(int);
#endif
#ifdef vms
#include <descrip.h>
#define MAILBOX "PLOT$MAILBOX"
#define pclose(f) fclose(f)
#endif /* vms */
#define isident(c) (isalnum(c) || (c) == '_')
#ifndef STDOUT
#define STDOUT 1
#endif
#define LBRACE '{'
#define RBRACE '}'
#define APPEND_TOKEN {token[t_num].length++; current++;}
#define SCAN_IDENTIFIER while (isident(expression[current + 1]))\
APPEND_TOKEN
static int t_num; /* number of token I'm working on */
/*
* scanner() breaks expression[] into lexical units, storing them in token[].
* The total number of tokens found is returned as the function value.
* Scanning will stop when '\0' is found in expression[], or when token[]
* is full.
*
* Scanning is performed by following rules:
*
* Current char token should contain
* ------------- -----------------------
* 1. alpha,_ all following alpha-numerics
* 2. digit 0 or more following digits, 0 or 1 decimal point,
* 0 or more digits, 0 or 1 'e' or 'E',
* 0 or more digits.
* 3. ^,+,-,/ only current char
* %,~,(,)
* [,],;,:,
* ?,comma
* $ for using patch (div)
* 4. &,|,=,* current char; also next if next is same
* 5. !,<,> current char; also next if next is =
* 6. ", ' all chars up until matching quote
* 7. # this token cuts off scanning of the line (DFK).
*
* white space between tokens is ignored
*/
int scanner(expression)
char expression[];
{
register int current; /* index of current char in expression[] */
register int quote;
char brace;
for (current = t_num = 0; expression[current] != '\0'; current++) {
again:
if(t_num+1>=token_table_size) {
/* leave space for dummy end token */
extend_token_table();
}
if (isspace(expression[current]))
continue; /* skip the whitespace */
token[t_num].start_index = current;
token[t_num].length = 1;
token[t_num].is_token = TRUE; /* to start with...*/
if (expression[current] == '`') {
substitute(&expression[current],MAX_LINE_LEN - current);
goto again;
}
/* allow _ to be the first character of an identifier */
if (isalpha(expression[current]) || expression[current] == '_') {
SCAN_IDENTIFIER;
} else if (isdigit(expression[current]) || expression[current] == '.'){
token[t_num].is_token = FALSE;
token[t_num].length = get_num(&expression[current]);
current += (token[t_num].length - 1);
} else if (expression[current] == LBRACE) {
token[t_num].is_token = FALSE;
token[t_num].l_val.type = CMPLX;
#ifdef __PUREC__
{ char l[80];
if ((sscanf(&expression[++current],"%lf,%lf%[ }]s",
&token[t_num].l_val.v.cmplx_val.real,
&token[t_num].l_val.v.cmplx_val.imag,
&l) != 3) || (!strchr(l, RBRACE)) )
int_error("invalid complex constant",t_num);
}
#else
if ((sscanf(&expression[++current],"%lf , %lf %c",
&token[t_num].l_val.v.cmplx_val.real,
&token[t_num].l_val.v.cmplx_val.imag,
&brace) != 3) || (brace != RBRACE))
int_error("invalid complex constant",t_num);
#endif
token[t_num].length += 2;
while (expression[++current] != RBRACE) {
token[t_num].length++;
if (expression[current] == '\0') /* { for vi % */
int_error("no matching '}'", t_num);
}
} else if (expression[current] == '\'' || expression[current] == '\"'){
token[t_num].length++;
quote = expression[current];
while (expression[++current] != quote) {
if (!expression[current]) {
expression[current] = quote;
expression[current+1] = '\0';
break;
} else
token[t_num].length++;
}
} else switch (expression[current]) {
case '#': /* DFK: add comments to gnuplot */
goto endline; /* ignore the rest of the line */
case '^':
case '+':
case '-':
case '/':
case '%':
case '~':
case '(':
case ')':
case '[':
case ']':
case ';':
case ':':
case '?':
case ',':
case '$': /* div */
break;
case '&':
case '|':
case '=':
case '*':
if (expression[current] == expression[current + 1])
APPEND_TOKEN;
break;
case '!':
case '<':
case '>':
if (expression[current + 1] == '=')
APPEND_TOKEN;
break;
default:
int_error("invalid character",t_num);
}
++t_num; /* next token if not white space */
}
endline: /* comments jump here to ignore line */
/* Now kludge an extra token which points to '\0' at end of expression[].
This is useful so printerror() looks nice even if we've fallen off the
line. */
token[t_num].start_index = current;
token[t_num].length = 0;
/* print 3+4 then print 3+ is accepted without
* this, since string is ignored if it is not
* a token
*/
token[t_num].is_token=TRUE;
return(t_num);
}
static int get_num(str)
char str[];
{
register int count = 0;
register long lval;
token[t_num].is_token = FALSE;
token[t_num].l_val.type = INTGR; /* assume unless . or E found */
while (isdigit(str[count]))
count++;
if (str[count] == '.') {
token[t_num].l_val.type = CMPLX;
while (isdigit(str[++count])) /* swallow up digits until non-digit */
;
/* now str[count] is other than a digit */
}
if (str[count] == 'e' || str[count] == 'E') {
token[t_num].l_val.type = CMPLX;
/* modified if statement to allow + sign in exponent
rjl 26 July 1988 */
count++;
if (str[count] == '-' || str[count] == '+')
count++;
if (!isdigit(str[count])) {
token[t_num].start_index += count;
int_error("expecting exponent",t_num);
}
while (isdigit(str[++count]))
;
}
if (token[t_num].l_val.type == INTGR) {
lval = atol(str);
if ((token[t_num].l_val.v.int_val = lval) != lval)
int_error("integer overflow; change to floating point",t_num);
} else {
token[t_num].l_val.v.cmplx_val.imag = 0.0;
token[t_num].l_val.v.cmplx_val.real = atof(str);
}
return(count);
}
#if defined(unix) || defined(vms) || defined(PIPES) || (defined(ATARI) && defined(__PUREC__)) || (defined(MTOS) && defined(__PUREC__))
static void substitute(str,max) /* substitute output from ` ` */
char *str;
int max;
{
register char *last;
register int i,c;
register FILE *f;
#ifdef AMIGA_AC_5
int fd;
#else
#if (defined(ATARI) && defined(__PUREC__)) || (defined(MTOS) && defined(__PUREC__))
char *atari_tmpfile;
char *atari_pgm[MAX_LINE_LEN+100];
#else
extern FILE *popen();
#endif /* ATARI && PUREC || MTOS && PUREC */
#endif /* AMIGA_AC_5 */
static char pgm[MAX_LINE_LEN+1],output[MAX_LINE_LEN+1];
#ifdef vms
int chan, one = 1;
static $DESCRIPTOR(pgmdsc,pgm);
static $DESCRIPTOR(lognamedsc,MAILBOX);
#endif /* vms */
i = 0;
last = str;
while (*(++last) != '`') {
if (*last == '\0')
int_error("unmatched `",t_num);
pgm[i++] = *last;
}
pgm[i] = '\0'; /* end with null */
max -= strlen(last); /* max is now the max length of output sub. */
#ifdef vms
pgmdsc.dsc$w_length = i;
if (!((vaxc$errno = sys$crembx(0,&chan,0,0,0,0,&lognamedsc)) & 1))
os_error("sys$crembx failed",NO_CARET);
if (!((vaxc$errno = lib$spawn(&pgmdsc,0,&lognamedsc,&one)) & 1))
os_error("lib$spawn failed",NO_CARET);
if ((f = fopen(MAILBOX,"r")) == NULL)
os_error("mailbox open failed",NO_CARET);
#else /* vms */
#if (defined(ATARI) && defined(__PUREC__)) || (defined(MTOS) && defined(__PUREC__))
if (system(NULL) == 0)
os_error("no command shell", NO_CARET);
if ((strlen(atari_tmpfile) + strlen(pgm) + 5) > MAX_LINE_LEN+100)
os_error("sorry, command to long", NO_CARET);
atari_tmpfile = tmpnam(NULL);
strcpy(atari_pgm, pgm);
strcat(atari_pgm, " >> ");
strcat(atari_pgm, atari_tmpfile);
system(atari_pgm);
if ((f = fopen(atari_tmpfile, "r")) == NULL)
#else
#ifdef AMIGA_AC_5
if ((fd = open(pgm,"O_RDONLY")) == -1)
#else
if ((f = popen(pgm,"r")) == NULL)
#endif
#endif /* ATARI && PUREC || MTOS && PUREC */
os_error("popen failed",NO_CARET);
#endif /* vms */
i = 0;
while ((c = getc(f)) != EOF) {
output[i++] = ((c == '\n') ? ' ' : c); /* newlines become blanks*/
if (i == max) {
#ifdef AMIGA_AC_5
(void) close(fd);
#else
#if (defined(ATARI) && defined(__PUREC__)) || (defined(MTOS) && defined(__PUREC__))
(void) fclose(f);
(void) unlink(atari_tmpfile);
#else
(void) pclose(f);
#endif /* ATARI && PUREC || MTOS && PUREC */
#endif
int_error("substitution overflow", t_num);
}
}
#ifdef AMIGA_AC_5
(void) close(fd);
#else
#if (defined(ATARI) && defined(__PUREC__)) || (defined(MTOS) && defined(__PUREC__))
(void) fclose(f);
(void) unlink(atari_tmpfile);
#else
(void) pclose(f);
#endif /* ATARI && PUREC || MTOS && PUREC */
#endif
if (i + strlen(last) > max)
int_error("substitution overflowed rest of line", t_num);
(void) strncpy(output+i,last+1,MAX_LINE_LEN-i);
/* tack on rest of line to output */
(void) strcpy(str,output); /* now replace ` ` with output */
screen_ok = FALSE;
}
#else /* unix || vms || PIPES || ATARI && PUREC */
static void substitute(str,max)
char *str;
int max;
{
char line[100];
int_error( strcat(strcpy(line,"substitution not supported by "),OS),t_num);
}
#endif /* unix || vms || PIPES || ATARI && PUREC */